#include "./include/clogic.h"

//设置协议映射表，NetPackMap(a)  TcpKernel::GetInstance()->m_NetPackMap[ a - _DEF_PACK_BASE ]
void CLogic::setNetPackMap()
{
    NetPackMap(_DEF_PACK_REGISTER_RQ)    =&CLogic::RegisterRq;//注册请求
    NetPackMap(_DEF_PACK_LOGIN_RQ)       =&CLogic::LoginRq;//登陆请求
    NetPackMap(_DEF_PACK_CREATEROOM_RQ)  =&CLogic::CreateRoomRq;//创建房间请求
    NetPackMap(_DEF_PACK_JOINROOM_RQ)    =&CLogic::JoinRoomRq;//加入房间请求
    NetPackMap(_DEF_PACK_LEAVEROOM_RQ)   =&CLogic::LeaveRoomRq;//离开房间请求
    NetPackMap(_DEF_PACK_AUDIO_FRAME)    =&CLogic::AudioFrameRq;//处理音频帧
    NetPackMap(_DEF_PACK_VIDEO_FRAME)    =&CLogic::VideoFrameRq;//处理视频帧
    NetPackMap(_DEF_PACK_AUDIO_REG)      =&CLogic::AudioReg;//音频注册请求
    NetPackMap(_DEF_PACK_VIDEO_REG)      =&CLogic::VideoReg;//视频注册请求
}

#define _DEF_COUT_FUNC_    cout << "clientfd:"<< clientfd << __func__ << endl

//注册请求
void CLogic::RegisterRq(sock_fd clientfd,char* szbuf,int nlen)
{
    //cout << "clientfd:"<< clientfd << __func__ << endl;
    _DEF_COUT_FUNC_;
    //1.拆包 获取tel password name
    STRU_REGISTER_RQ* rq = (STRU_REGISTER_RQ*)szbuf;
    STRU_REGISTER_RS rs;
    char sqlStr[1024]={0};
    sprintf(sqlStr,"select tel from t_user where tel = '%s';",
            rq->m_tel);
    list<string> resList;
    if(!m_sql->SelectMysql(sqlStr,1,resList))
    {
        cout<<"selectMysql error:"<<sqlStr<<endl;
        return;
    }
    if(resList.size()>0)//已经有这个手机号了,返回用户已存在
    {
        rs.m_result = tel_is_exist;
    }
    else
    {
        //查表 t_user 根据tel查tel
        sprintf(sqlStr,"select name from t_user where name = '%s';",
                rq->m_name);
        resList.clear();
        if(!m_sql->SelectMysql(sqlStr,1,resList))
        {
            cout<<"selectMysql error:"<<sqlStr<<endl;
            return;
        }
        if(resList.size()>0)//已经有这个昵称了,返回昵称已存在
        {
            rs.m_result = name_is_exist;
        }
        else//没有 写入数据库 返回注册成功
        {
            rs.m_result = register_success;
            sprintf(sqlStr,"insert into t_user(tel,password,name,icon,feeling) "
                           "values('%s','%s','%s','%d','%s');",
                    rq->m_tel,rq->m_password,rq->m_name,1,"nothing");
            if(!m_sql->UpdataMysql(sqlStr))
            {
                cout<<"updataMysql error:"<<sqlStr<<endl;
                return;
            }
        }
    }
    m_tcp->SendData(clientfd,(char*)&rs,sizeof(rs));
}

//登录请求
void CLogic::LoginRq(sock_fd clientfd ,char* szbuf,int nlen)
{
    _DEF_COUT_FUNC_;
    //拆包 获取tel password
    STRU_LOGIN_RQ* rq = (STRU_LOGIN_RQ*)szbuf;
    STRU_LOGIN_RS rs;
    //根据tel查password和id,判断
    char sqlStr[1024]={0};
    sprintf(sqlStr,"select password,id,name from t_user where tel = '%s';",
            rq->m_tel);
    list<string> resList;
    if(!m_sql->SelectMysql(sqlStr,3,resList))
    {
        cout<<"selectMysql error:"<<sqlStr<<endl;
        return;
    }
    if(resList.size() == 0)//没有该手机号对应的用户
    {
        rs.m_result = user_not_exist;
    }
    else
    {
        if(strcmp(rq->m_password,resList.front().c_str()) != 0)//密码不一致
        {
            rs.m_result = password_error;
        }
        else
        {
            resList.pop_front();
            //登录成功,sock保存起来,存到id->sock的映射,便于通信
            int id = atoi(resList.front().c_str());
            resList.pop_front();
            UserInfo* pInfo = new UserInfo;
            pInfo->m_id = id;
            pInfo->m_roomid = 0;
            pInfo->m_sockfd = clientfd;
            strcpy(pInfo->m_username,resList.front().c_str());
            resList.pop_front();

            //判断id是否在线,如果在线则强制下线,不在线则添加
            if(m_mapIdToUserInfo.IsExist(pInfo->m_id))
            {
                //强制下线 todo
            }
            m_mapIdToUserInfo.insert(pInfo->m_id,pInfo);
            //返回包
            rs.m_result = login_success;
            rs.m_userid = id;
            strcpy(rs.m_name,pInfo->m_username);
        }
    }
    cout << "first" <<endl;
    m_tcp->SendData(clientfd,(char*)&rs,sizeof(rs));
}

//创建房间请求
void CLogic::CreateRoomRq(sock_fd clientfd, char *szbuf, int nlen)
{
    _DEF_COUT_FUNC_;
    STRU_CREATEROOM_RQ* rq = (STRU_CREATEROOM_RQ*)szbuf;
    //随机数得到房间号,看当前这个房间号是否存在,可能循环随机
    int roomid = 0;
    do
    {
        roomid = rand()%99999999 + 1;
    }while(m_mapIdToRoomid.IsExist(roomid) == true);
    cout<<"创建新的房间号:"<<roomid<<endl;
    //map roomid->list
    list<int> lst;
    lst.emplace_back(rq->m_userid);
    m_mapIdToRoomid.insert(roomid,lst);
    //回复
    STRU_CREATEROOM_RS rs;
    rs.m_roomid = roomid;
    rs.m_result = 1;

    m_tcp->SendData(clientfd,(char*)&rs,sizeof(rs));
}

//加入房间请求
void CLogic::JoinRoomRq(sock_fd clientfd, char *szbuf, int nlen)
{
    _DEF_COUT_FUNC_;
    STRU_JOINROOM_RQ* rq = (STRU_JOINROOM_RQ*)szbuf;
    STRU_JOINROOM_RS rs;
    //查看房间是否存在,不存在返回加入失败
    if(m_mapIdToRoomid.IsExist(rq->m_roomid) == false)
    {
        rs.m_result = 0;
        m_tcp->SendData(clientfd,(char*)&rs,sizeof(rs));
        return;
    }
    rs.m_result = 1;
    rs.m_roomid = rq->m_roomid;
    m_tcp->SendData(clientfd,(char*)&rs,sizeof(rs));

    if(m_mapIdToUserInfo.IsExist(rq->m_userid) == false)
    {
        return;
    }
    UserInfo* joiner = nullptr;
    m_mapIdToUserInfo.find(rq->m_userid,joiner);
    STRU_ROOM_MEMBER_RQ joinrq;
    joinrq.m_userid = rq->m_userid;
    strcpy(joinrq.szUserName,joiner->m_username);

    //给自己用于更新自己的信息
    //m_tcp->SendData(clientfd,(char*)&joinrq,sizeof(joinrq));
    //根据房间号拿到房间成员列表,遍历列表
    list<int> lstRoom;  //m_mapIdToRoomid.rq->m_roomid];
    m_mapIdToRoomid.find(rq->m_roomid,lstRoom);
    //遍历列表,把加入人的信息发给房间里的每个成员
    //房间内成员每个人信息也发给加入人
    for(auto it = lstRoom.begin();it!=lstRoom.end();it++)
    {
        int memid = *it;
        if(m_mapIdToUserInfo.IsExist(memid)==false)
        {
            continue;
        }
        UserInfo* p_meminfo = nullptr;
        m_mapIdToUserInfo.find(memid,p_meminfo);
        //加入人的信息
        STRU_ROOM_MEMBER_RQ memrq;
        memrq.m_userid = p_meminfo->m_id;
        strcpy(memrq.szUserName,p_meminfo->m_username);
        //把加入人的信息发给房间里的每个成员
        m_tcp->SendData(p_meminfo->m_sockfd,(char*)&joinrq,sizeof(joinrq));
        m_tcp->SendData(clientfd,(char*)&memrq,sizeof(memrq));
    }
    //将加入的成员添加到房间列表
    lstRoom.emplace_back(rq->m_userid);
    m_mapIdToRoomid.insert(rq->m_roomid,lstRoom);
}

//离开房间请求
void CLogic::LeaveRoomRq(sock_fd clientfd, char *szbuf, int nlen)
{
    //拆包
    STRU_LEAVEROOM_RQ* rq = (STRU_LEAVEROOM_RQ*)szbuf;
    //看房间是否存在,如果存在获取用户列表
    if(m_mapIdToRoomid.IsExist(rq->m_roomid) == false)
    {
        return;
    }
    list<int> lst;
    m_mapIdToRoomid.find(rq->m_roomid,lst);
    //遍历每个用户,给在线的用户转发
    for(auto it = lst.begin();it!=lst.end();)
    {
        int userid = *it;
        if(userid == rq->m_userid)//如果是自己,从房间列表中移除
        {
            it = lst.erase(it);
        }
        else
        {
            if(m_mapIdToUserInfo.IsExist(userid) == true)
            {
                UserInfo* info = nullptr;
                m_mapIdToUserInfo.find(userid,info);
                m_tcp->SendData(info->m_sockfd,szbuf,nlen);
            }
            ++it;
        }
    }
    //判断列表结点数,如果为0则从map中去掉,解散房间
    if(lst.size() == 0)
    {
        m_mapIdToRoomid.erase(rq->m_roomid);
        return;
    }
    //更新房间成员列表
    m_mapIdToRoomid.insert(rq->m_roomid,lst);
}

//音频数据帧
//成员描述
//int type;
//int userid;
//int roomid;
//int min;
//int sec;
//int msec;
//QByteArray audioFrame

//处理音频帧
void CLogic::AudioFrameRq(sock_fd clientfd, char *szbuf, int nlen)
{
    //拆包
    char* tmp = szbuf;
    tmp+=sizeof(int);//跳过第一个整型(包类型)

    int selfid = *(int*)tmp;
    tmp+=sizeof(int);//获取userid

    int roomid = *(int*)tmp;//获取roomid
    //看房间是否存在
    if(m_mapIdToRoomid.IsExist(roomid) == false)
    {
        return;
    }
    list<int> lst;
    m_mapIdToRoomid.find(roomid,lst);
    //获取成员列表
    for(auto it = lst.begin();it!=lst.end();++it)
    {
        //看是否在线,转发
        int userid = *it;
        if(userid == selfid)
        {
            continue;
        }
        if(m_mapIdToUserInfo.IsExist(userid) == false)
        {
            continue;
        }
        UserInfo* userinfo = nullptr;
        m_mapIdToUserInfo.find(userid,userinfo);
        //原样转发
        m_tcp->SendData(userinfo->m_audiofd,szbuf,nlen);
    }
}

//视频数据帧
//成员描述
//int type;
//int userid;
//int roomid;
//int min;
//int sec;
//int msec;
//QByteArray videoFrame

//处理视频帧
void CLogic::VideoFrameRq(sock_fd clientfd, char *szbuf, int nlen)
{
    //拆包
    char* tmp = szbuf;
    tmp+=sizeof(int);//跳过第一个整型(包类型)

    int selfid = *(int*)tmp;
    tmp+=sizeof(int);//获取userid

    int roomid = *(int*)tmp;//获取roomid
    //看房间是否存在
    if(m_mapIdToRoomid.IsExist(roomid) == false)
    {
        return;
    }
    list<int> lst;
    m_mapIdToRoomid.find(roomid,lst);
    //获取成员列表
    for(auto it = lst.begin();it!=lst.end();++it)
    {
        //看是否在线,转发
        int userid = *it;
        if(userid == selfid)
        {
            continue;
        }
        if(m_mapIdToUserInfo.IsExist(userid) == false)
        {
            continue;
        }
        UserInfo* userinfo = nullptr;
        m_mapIdToUserInfo.find(userid,userinfo);
        //原样转发
        m_tcp->SendData(userinfo->m_videofd,szbuf,nlen);
    }
}

//登陆时注册音频socket
void CLogic::AudioReg(sock_fd clientfd, char *szbuf, int nlen)
{
    cout<<"注册音频";
    _DEF_COUT_FUNC_;
    STRU_AUDIO_REG* rq = (STRU_AUDIO_REG*)szbuf;
    int user_id = rq->m_userid;
    if(m_mapIdToUserInfo.IsExist(user_id) == true)
    {
        UserInfo* user = nullptr;
        m_mapIdToUserInfo.find(user_id,user);
        user->m_audiofd = clientfd;
    }
}

//登陆时注册视频socket
void CLogic::VideoReg(sock_fd clientfd, char *szbuf, int nlen)
{
    cout<<"注册视频";
    _DEF_COUT_FUNC_;
    STRU_VIDEO_REG* rq = (STRU_VIDEO_REG*)szbuf;
    int user_id = rq->m_userid;
    if(m_mapIdToUserInfo.IsExist(user_id) == true)
    {
        UserInfo* user = nullptr;
        m_mapIdToUserInfo.find(user_id,user);
        user->m_videofd = clientfd;
    }
}














